package com.nosnow.ucenter.controller;

import com.google.gson.Gson;
import com.nosnow.common.utils.JwtUtils;
import com.nosnow.handler.SnowflakeException;
import com.nosnow.ucenter.entity.UcenterMember;
import com.nosnow.ucenter.service.UcenterMemberService;
import com.nosnow.ucenter.utils.ConstantWxUtils;
import com.nosnow.ucenter.utils.HttpClientUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;

/**
 * @author by bingHeng
 * @version 1.0
 * @Create 2020/5/1 18:59
 */

@Controller // 只需要请求地址，不需要返回json数据，因此使用Controller注解
@RequestMapping("/ucenter/wx") // /api/ucenter/wx  测试微信登录，接口地址改为和项目一致
public class WxApiController {

    @Autowired
    private UcenterMemberService memberService;

    @GetMapping("callback")
    public String callback(String code, String state) {
        try {
            // 1. 获取code值，临时票据，类似于验证码， 拿着code请求微信固定的地址，得到两个值accsess_token 和 openid
            String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"
                    + "?appid=%s"
                    + "&secret=%s"
                    + "&code=%s"
                    + "&grant_type=authorization_code";

            // 2. 拼接三个参数： id 秘钥 和code值
            String accessTokenUrl = String.format(baseAccessTokenUrl, ConstantWxUtils.WX_OPEN_APP_ID, ConstantWxUtils.WX_OPEN_APP_SECRET, code);

            // 3. 请求这个拼接好的地址，得到返回两个值access_token和 openid, 使用httpclient发送请求，得到返回结果
            String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);

            // 4. 从accessTokenInfo字符串获取出来两个值 access_token 和 openid, 把accessTokenInfo字符串转换map集合，根据map里面key获取对应值
            Gson gson = new Gson();
            HashMap mapAccessToken = gson.fromJson(accessTokenInfo, HashMap.class);
            String access_token = (String)mapAccessToken.get("access_token");
            String openid = (String)mapAccessToken.get("openid");

            // 5. 将扫码人的信息添加到数据库里面， 判断数据表里面是否存在相同微信信息，根据openid判断
            UcenterMember member = memberService.getOpenIdMember(openid);
            if(member == null) {
                // 5.1 拿着得到access_token 和 openid，再去请求微信提供固定的地址，获取到扫描人信息 访问微信的资源服务器，获取用户信息
                String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" + "?access_token=%s" + "&openid=%s";
                String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);

                // 5.2 发送请求
                String userInfo = HttpClientUtils.get(userInfoUrl);

                // 5.3 获取返回userInfo字符串扫描人信息
                HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
                member = new UcenterMember();
                member.setOpenid(openid);
                member.setNickname((String)userInfoMap.get("nickname"));
                member.setAvatar((String)userInfoMap.get("headimgurl"));
                member.setSex(((Double)userInfoMap.get("sex")).intValue());
                memberService.save(member);
            }
            // 6. 使用jwt根据member对象生成token字符串, 因为端口号不同存在跨域问题，cookie不能跨域，所以这里使用url重写
            String jwtToken = JwtUtils.getJwtToken(member.getId(), member.getNickname());

            // localhost:3000  目前前端项目的访问地址
            return "redirect:http://localhost:3000?token="+jwtToken;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SnowflakeException(20001,"登录失败");
        }
    }


    /**
     * 生成登录二维码
     * @param session
     * @return
     */
    @GetMapping("login")
    public String genQrConnect(HttpSession session) {
        try {
            // 1. 微信开放平台授权baseUrl  %s  占位符
            String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                    "?appid=%s" +
                    "&redirect_uri=%s" +
                    "&response_type=code" +
                    "&scope=snsapi_login" +
                    "&state=%s" +
                    "#wechat_redirect";

            // 2. 回调地址
            String url = String.format(baseUrl, ConstantWxUtils.WX_OPEN_APP_ID, URLEncoder.encode(ConstantWxUtils.WX_OPEN_REDIRECT_URL, "utf-8"), "snowflake");

            // TODO 3. 防止csrf攻击（跨站请求伪造攻击）
            // String state = UUID.randomUUID().toString().replaceAll("-", ""); // 一般情况下会使用一个随机数
            String state = "imhelen"; //为了让大家能够使用我搭建的外网的微信回调跳转服务器，这里填写你在ngrok的前置域

            // TODO 4. 采用redis等进行缓存state， 使用sessionId为key 30分钟后过期

            return "redirect:" + url;
        } catch (UnsupportedEncodingException e) {
            throw new SnowflakeException(20001, e.getMessage());
        }
    }
}
